home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # ClientAppli.c
- #
- # derived from MPW 3.1's "Sample", a MultiFinder-Aware Simple Sample Application
- #
- # Demostrates how to communicate with A/ROSE tasks
- #
- # Refer to the original source code in the MPW CExamples folder for more comments
- #
- # Components:
- # ClientAppli.c
- # ClientAppli.r
- # ClientAppli.h
- # ClientAppli.make
- #
- # MPW build commands:
- #
- C ClientAppli.c
- Link ClientAppli.c.o ∂
- "{CLibraries}"CRuntime.o ∂
- "{CLibraries}"CInterface.o ∂
- "{Libraries}"Interface.o ∂
- "{AROSEPrep}"IPCGlue.o ∂
- -o ClientAppli
- Rez -rd -o ClientAppli ClientAppli.r -append
- #
- ------------------------------------------------------------------------------*/
-
-
-
- #include <Types.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Desk.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <SegLoad.h>
- #include <Files.h>
- #include <OSUtils.h>
- #include <OSEvents.h>
- #include <DiskInit.h>
- #include <Packages.h>
- #include <Traps.h>
- #include <Strings.h>
-
- #include "ClientAppli.h" // bring in all the #defines for ClientAppli
-
- //---------------------------------------------------------------------------
- // A/ROSE declarations (from "os.h"):
-
- typedef long tid_type;
-
- struct mMessage
- {
- struct mMessage *mNext;
- long mId;
- short mCode;
- short mStatus;
- unsigned short mPriority;
- tid_type mFrom;
- tid_type mTo;
- unsigned long mSData [3];
- unsigned long mOData [3];
- long mDataSize; // Size of data buffer in bytes. set to negative
- // size of buffer if buffer is shared
- // between tasks. eg. Buffer cannot be copied
- char *mDataPtr;
- };
-
- typedef struct mMessage mMessage;
-
- #define OS_MATCH_ALL 0 // on receive match anything
- #define OS_NO_TIMEOUT 0 // receive waits forever for message
-
- // and some #define's from "managers.h":
-
- #define OS_UNKNOWN_MESSAGE (1<<8) // unknown message
- #define Machine_Visible 0 // Register_task Machine visible flag
-
- #define ICC_GETCARDS 150 // Get list of active cards and their name mgr TID
-
- //---------------------------------------------------------------------------
-
-
- // global variables
-
- SysEnvRec gMac; // set up by Initialize
- Boolean gHasWaitNextEvent; // set up by Initialize
- Boolean gInBackground; // maintained by Initialize and DoEvent
- long gSleepVal; // MultiFinder sleep value
- // for WaitNextEvent
-
- short gReceived; // number of received/sent messages
- short gSent;
- tid_type gTID, // my task identifier returned by OpenQueue()
- gServerTID; // the task identifier of the required server task
-
- WindowPtr gMyWindow; // only one window
- ControlHandle ghReset, ghSend; // two buttons in the window
-
- tid_type gCards[16]; // array of Name Manager TID's in NuBus slots
-
- // Prototypes for parameter type checking.
-
- void EventLoop( void );
- void DoEvent( EventRecord *event );
- void DoUpdate( WindowPtr window );
- void DoActivate( WindowPtr window, Boolean becomingActive );
- void DoContentClick( WindowPtr window, EventRecord *event);
- void DrawWindow( WindowPtr window );
- void AdjustMenus( void );
- void DoMenuCommand( long menuResult );
- Boolean DoCloseWindow( WindowPtr window );
- void Terminate( void );
- void Initialize( void );
- void ForceEnvirons( void );
- Boolean IsAppWindow( WindowPtr window );
- Boolean IsDAWindow( WindowPtr window );
- Boolean TrapAvailable( short tNumber, TrapType tType );
- void AlertUser( short error );
- void BigBadError( short error );
- void NumToHex( long n, short d, char *s);
- short AROSEPrep();
- tid_type FindServer(char *name, char *type);
- Boolean AskICCM();
- void TaskProcessing();
- void SendaMessage(short msgCode, tid_type msgDest);
- void UpdateDisplay();
-
- // A/ROSE prototypes: --------------------
-
- extern char Register_Task(char *, char *, short);
- extern mMessage *GetMsg(void);
- extern mMessage *Receive();
- extern void SwapTID(mMessage *);
- extern void Send(mMessage *);
- extern void FreeMsg();
-
- extern tid_type GetTID(void);
- extern tid_type GetICCTID(void);
- extern tid_type Lookup_Task(char *, char *, tid_type, unsigned short *);
-
- extern tid_type OpenQueue();
- extern void CloseQueue();
- //----------------------------------------
-
- // Define HiWrd and LoWrd macros for efficiency.
- #define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF)
- #define LoWrd(aLong) ((aLong) & 0xFFFF)
-
-
- extern void _DataInit();
-
-
- #pragma segment Main
- main()
- {
- UnloadSeg((Ptr) _DataInit); // note that _DataInit must not be in Main!
-
- MaxApplZone(); // expand the heap so code segments load at the top
-
- Initialize(); // initialize the program
- UnloadSeg((Ptr) Initialize); // note that Initialize must not be in Main!
-
- EventLoop(); // call the main event loop
- }
-
-
- #pragma segment Main
- void EventLoop()
- {
- Boolean gotEvent;
- EventRecord event;
-
- do {
- gotEvent = WaitNextEvent(everyEvent, &event, gSleepVal, nil);
- if ( gotEvent )
- DoEvent(&event);
-
- //=========================
- TaskProcessing(); // <<<<<<<<<< this is the A/ROSE task !
- //=========================
-
- } while ( true ); // loop forever; we quit via Terminate/ExitToShell
- } //EventLoop
-
-
- #pragma segment Main
- void DoEvent(event)
- EventRecord *event;
- {
- short part, err;
- WindowPtr window;
- char key;
- Point aPoint;
-
- switch ( event->what ) {
- case mouseDown:
- part = FindWindow(event->where, &window);
- switch ( part ) {
- case inMenuBar: // process a mouse menu command (if any)
- AdjustMenus();
- DoMenuCommand(MenuSelect(event->where));
- break;
- case inSysWindow: // let the system handle the mouseDown
- SystemClick(event, window);
- break;
- case inContent:
- if ( window != FrontWindow() ) {
- SelectWindow(window);
- } else
- DoContentClick(window, event);
- break;
- case inDrag: // pass screenBits.bounds to get all gDevices
- DragWindow(window, event->where, &qd.screenBits.bounds);
- break;
- }
- break;
- case keyDown:
- case autoKey: // check for menukey equivalents
- key = event->message & charCodeMask;
- if ( event->modifiers & cmdKey ) // Command key down
- if ( event->what == keyDown ) {
- AdjustMenus(); // enable/disable/check menu items properly
- DoMenuCommand(MenuKey(key));
- }
- break;
- case activateEvt:
- DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
- break;
- case updateEvt:
- DoUpdate((WindowPtr) event->message);
- break;
- case diskEvt:
- if ( HiWord(event->message) != noErr ) {
- SetPt(&aPoint, kDILeft, kDITop);
- err = DIBadMount(aPoint, event->message);
- // so that the user can format a floppy.
- }
- break;
- case kOSEvent:
- switch ((event->message >> 24) & 0x0FF) { // high byte of message
- case kSuspendResumeMessage: // suspend/resume is also an activate/deactivate
- gInBackground = (event->message & kResumeMask) == 0;
- DoActivate(FrontWindow(), !gInBackground);
- break;
- }
- break;
- }
- } //DoEvent
-
-
- #pragma segment Main
- void DoUpdate(window)
- WindowPtr window;
- {
- if ( IsAppWindow(window) ) {
- BeginUpdate(window); // this sets up the visRgn
- if ( ! EmptyRgn(window->visRgn) ) // draw if updating needs to be done
- DrawWindow(window);
- EndUpdate(window);
- }
- } //DoUpdate
-
-
- #pragma segment Main
- void DoActivate(window, becomingActive)
- WindowPtr window;
- Boolean becomingActive;
- {
- if ( IsAppWindow(window) ) {
- if ( becomingActive )
- ; // do whatever you need to at activation
- else
- ; // do whatever you need to at deactivation
- }
- } //DoActivate
-
- #pragma segment Main
- void DoContentClick(window, event)
- WindowPtr window;
- EventRecord *event;
- {
- Point mouse;
- ControlHandle control;
- short dummy;
-
- if ( IsAppWindow(window) ) {
- SetPort(window);
- mouse = event->where; // get the click position
- GlobalToLocal(&mouse);
- if ( FindControl(mouse, window, &control) == inButton) {
- dummy = TrackControl(control, mouse, nil);
- if (control == ghReset) {
- SendaMessage(RESETCODE,gServerTID);
- gReceived = 0;
- gSent = 0;
- }
- else if (control == ghSend) // what else ?
- SendaMessage(DUMMYCODE, gServerTID);
- }
- }
- } //DoContentClick
-
-
- #pragma segment Main
- void DrawWindow(window)
- WindowPtr window;
- {
- Str255 s;
- Rect countRect;
- GrafPtr savePort;
-
- GetPort(&savePort);
-
- SetPort(window);
- TextFont(monaco);
- TextSize(12);
-
- SetRect(&countRect,150,80,200,125);
- EraseRect(&countRect); // reduce the flicker ...
-
- GetIndString(s, rWndStrings, 1);
- MoveTo(20,20);
- DrawString(s);
- NumToHex(gTID, 8, s);
- DrawString(s);
-
- GetIndString(s, rWndStrings, 2);
- MoveTo(20,40);
- DrawString(s);
-
- GetIndString(s, rWndStrings, 5); // funny numbering scheme - compare TaskSample.r ...
- MoveTo(20,70);
- DrawString(s);
- NumToHex(gServerTID, 8, s);
- DrawString(s);
-
- GetIndString(s, rWndStrings, 3);
- MoveTo(20,100);
- DrawString(s);
- NumToString(gReceived, s);
- DrawString(s);
-
- GetIndString(s, rWndStrings, 4);
- MoveTo(20,120);
- DrawString(s);
- NumToString(gSent, s);
- DrawString(s);
-
- DrawControls(window);
- SetPort(savePort);
-
- } //DrawWindow
-
-
- #pragma segment Main
- void AdjustMenus()
- {
- WindowPtr window;
- MenuHandle menu;
-
- window = FrontWindow();
-
- menu = GetMHandle(mFile);
- if ( IsDAWindow(window) ) // we can allow desk accessories to be closed from the menu
- EnableItem(menu, iClose);
- else
- DisableItem(menu, iClose); // but not our only window
-
- menu = GetMHandle(mEdit);
- if ( IsDAWindow(window) ) { // a desk accessory might need the edit menu…
- EnableItem(menu, iUndo);
- EnableItem(menu, iCut);
- EnableItem(menu, iCopy);
- EnableItem(menu, iClear);
- EnableItem(menu, iPaste);
- } else { // …but we don’t use it
- DisableItem(menu, iUndo);
- DisableItem(menu, iCut);
- DisableItem(menu, iCopy);
- DisableItem(menu, iClear);
- DisableItem(menu, iPaste);
- }
- menu = GetMHandle(mSleep);
- if (gSleepVal == 0) {
- CheckItem(menu,iNoSleep,true);
- CheckItem(menu,i60Ticks,false);
- }
- else {
- CheckItem(menu,iNoSleep,false);
- CheckItem(menu,i60Ticks,true);
- }
- } //AdjustMenus
-
-
- #pragma segment Main
- void DoMenuCommand(menuResult)
- long menuResult;
- {
- short menuID; // the resource ID of the selected menu
- short menuItem; // the item number of the selected menu
- short itemHit;
- Str255 daName;
- short daRefNum;
- Boolean handledByDA;
-
- menuID = HiWord(menuResult); // use macros for efficiency to...
- menuItem = LoWord(menuResult); // get menu item number and menu number
- switch ( menuID ) {
- case mApple:
- switch ( menuItem ) {
- case iAbout: // bring up alert for About
- itemHit = Alert(rAboutAlert, nil);
- break;
- default: // all non-About items in this menu are DAs
- // type Str255 is an array in MPW 3
- GetItem(GetMHandle(mApple), menuItem, daName);
- daRefNum = OpenDeskAcc(daName);
- break;
- }
- break;
- case mFile:
- switch ( menuItem ) {
- case iClose:
- DoCloseWindow(FrontWindow());
- break;
- case iQuit:
- Terminate();
- break;
- }
- break;
- case mEdit: // call SystemEdit for DA editing & MultiFinder
- handledByDA = SystemEdit(menuItem-1); // since we don’t do any Editing
- break;
- case mSleep:
- switch ( menuItem ) {
- case iNoSleep:
- gSleepVal = 0;
- break;
- case i60Ticks:
- gSleepVal = 60;
- break;
- }
- break;
- }
- HiliteMenu(0); // unhighlight what MenuSelect (or MenuKey) hilited
- } //DoMenuCommand
-
-
-
- #pragma segment Main
- Boolean DoCloseWindow(window)
- WindowPtr window;
- {
- if ( IsDAWindow(window) )
- CloseDeskAcc(((WindowPeek) window)->windowKind);
- else if ( IsAppWindow(window) )
- CloseWindow(window);
- return true;
- } //DoCloseWindow
-
-
-
- #pragma segment Main
- void Terminate()
- {
- WindowPtr aWindow;
- Boolean closed;
-
- CloseQueue(); // Clean up interaction with A/ROSE Prep
- closed = true;
- do {
- aWindow = FrontWindow(); // get the current front window
- if (aWindow != nil)
- closed = DoCloseWindow(aWindow); // close this window
- }
- while (closed && (aWindow != nil));
- if (closed)
- ExitToShell(); // exit if no cancellation
- } //Terminate
-
-
-
- #pragma segment Initialize
- void Initialize()
- {
- Handle menuBar;
- long total, contig;
- EventRecord event;
- short count, result;
- Ptr windowP;
-
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- gInBackground = false;
- gSleepVal = 60;
-
- // This next bit of code is necessary to allow the default button of our
- // alert be outlined.
-
- for (count = 1; count <= 3; count++)
- EventAvail(everyEvent, &event);
-
- SysEnvirons(kSysEnvironsVersion, &gMac);
-
- if (gMac.machineType < 0)
- BigBadError(eWrongMachine);
-
- if (! TrapAvailable(_WaitNextEvent, ToolTrap))
- BigBadError(eWrongMachine);
-
- if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap)
- BigBadError(eSmallSize);
-
- // ZeroScrap();
-
- PurgeSpace(&total, &contig);
- if (total < kMinSpace)
- BigBadError(eNoMemory);
-
- result = AROSEPrep();
- if (result != noErr) {
- if (gTID > 0) // if we registered with .IPC --
- CloseQueue(); // better clean up - we are going to Exit
-
- BigBadError(result);
- }
-
- windowP = NewPtr(sizeof(WindowRecord)); // we allocate storage ourselves
- if ( windowP == nil )
- BigBadError(eNoWindow);
-
- gMyWindow = GetNewWindow(rWindow, windowP, (WindowPtr) -1);
- ghReset = GetNewControl(rResetBtn, gMyWindow); // Reset counts button
- ghSend = GetNewControl(rSendBtn, gMyWindow); // Send message button
-
- if ((ghReset == nil) | (ghSend == nil))
- BigBadError(eNoWindow);
-
- menuBar = GetNewMBar(rMenuBar); // read menus into menu bar
- if ( menuBar == nil )
- BigBadError(eNoMemory);
- SetMenuBar(menuBar); // install menus
- DisposHandle(menuBar);
- AddResMenu(GetMHandle(mApple), 'DRVR'); // add DA names to Apple menu
- DrawMenuBar();
-
- } //Initialize
-
-
- #pragma segment Main
- Boolean IsAppWindow(window)
- WindowPtr window;
- {
- short windowKind;
-
- if ( window == nil )
- return false;
- else { // application windows have windowKinds = userKind (8)
- windowKind = ((WindowPeek) window)->windowKind;
- return (windowKind = userKind);
- }
- } //IsAppWindow
-
-
- #pragma segment Main
- Boolean IsDAWindow(window)
- WindowPtr window;
- {
- if ( window == nil )
- return false;
- else // DA windows have negative windowKinds
- return ((WindowPeek) window)->windowKind < 0;
- } //IsDAWindow
-
-
- #pragma segment Initialize
- Boolean TrapAvailable(tNumber,tType)
- short tNumber;
- TrapType tType;
- {
- if ( ( tType == ToolTrap ) &&
- ( gMac.machineType > envMachUnknown ) &&
- ( gMac.machineType < envMacII ) ) { // it's a 512KE, Plus, or SE
- tNumber = tNumber & 0x03FF;
- if ( tNumber > 0x01FF ) // which means the tool traps
- tNumber = _Unimplemented; // only go to 0x01FF
- }
- return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
- } //TrapAvailable
-
-
- #pragma segment Main
- void AlertUser( short error)
- {
- short itemHit;
- Str255 errMsg;
-
- SetCursor(&qd.arrow);
- if ((error>0)&&(error<=kLastErrStr)) {
- GetIndString(errMsg, rErrStrings, error);
- ParamText(errMsg, "", "", "");
- }
- else {
- NumToString(error, &errMsg);
- ParamText("\pUnknown error", errMsg, "", "");
- }
-
- itemHit = Alert(rUserAlert, nil);
- } // AlertUser
-
- #pragma segment Main
- void BigBadError( short error)
- {
- AlertUser(error);
- ExitToShell();
- }
-
-
- #pragma segment Main
- void NumToHex( long n, short d, char *s) // I hate this @#%@ !
- // s must point to at least d+1 free bytes - returns Pascal String of length d
- // requires d > 0
- {
- short c;
-
- s[0] = d;
- do {
- c = (n & 0x0F) + 48;
- if (c>57)
- c = c+7;
- s[d--] = (char) c;
- n = n>>4;
- } while (d > 0);
- }
-
- #pragma segment Main
- void StringCopy(char *s, char *t)
- {
- short n= (*t++ = *s++);
- while (n-- >0)
- *t++ = *s++;
- }
-
- #pragma segment Initialize
- short AROSEPrep()
- {
- StringHandle sh;
- Str255 clientName = "?", clientType = "?",
- taskName = "?", taskType = "?"; // wasting lots of RAM, eh ?
-
-
- gServerTID = 0; // as long as we don't know
-
- sh = GetString(rClientName);
- if (sh != nil)
- StringCopy(*sh,clientName);
- sh = GetString(rClientType);
- if (sh != nil)
- StringCopy(*sh,clientType);
-
- gTID = OpenQueue(0);
- if (gTID == 0) {
- return(eNoAROSE);
- }
- if (!Register_Task (p2cstr(&clientName), p2cstr(&clientType), Machine_Visible))
- AlertUser(eRegister);
-
- sh = GetString(rTaskName);
- if (sh != nil)
- StringCopy(*sh,taskName);
- sh = GetString(rTaskType);
- if (sh != nil)
- StringCopy(*sh,taskType);
- if (gServerTID = FindServer(p2cstr(&taskName), p2cstr(&taskType)))
- return(noErr);
- else return(eNoServer);
- }
-
-
- tid_type FindServer(char *name, char *type)
- // compare this with "ShowTasks.c" !
- {
- short slot;
- tid_type tid, // will be (hopefully) our gServerTID
- sTID; // the Name Manager TID for a given slot
- unsigned short index;
-
-
- if (! AskICCM()) {
- AlertUser(eICCMproblem);
- return 0;
- }
-
- slot = 0;
- tid = 0;
- do {
- index = 0;
- if (sTID = gCards[slot++])
- tid = Lookup_Task (name, type, sTID, &index);
- } while ((tid == 0) && (slot < 16));
- return tid;
- }
-
-
- Boolean AskICCM()
- {
- Boolean result;
- mMessage *m;
-
- if (GetICCTID() == 0)
- return(false);
-
- if ((m = GetMsg ()) == 0)
- return(false);
-
- m -> mTo = GetICCTID ();
- m -> mCode = ICC_GETCARDS;
- m -> mDataPtr = (char *) gCards;
- m -> mDataSize = sizeof (tid_type) * 16;
- Send (m);
- m = Receive (OS_MATCH_ALL, OS_MATCH_ALL, ICC_GETCARDS+1, OS_NO_TIMEOUT, 0);
-
- result = (m -> mStatus == 0); // slotInfo is in cards[0..15] !
- FreeMsg(m);
- return(result);
-
- } // AskICCM()
-
-
- void TaskProcessing()
- // Here I am a "client", i.e. all I am interested in is getting back the message I sent
- // to the "server" earlier. Presumably, I requested something from the server,
- // and he is supposed to come back with the reply.
- {
- GrafPtr savePort;
- mMessage *m;
-
- m = Receive(0L, 0L, 0L, -1L, nil); // -1L: return without waiting (OS_NO_TIMEOUT)
- // nil: no completion routine
-
- // in A/ROSE this would be: m = Receive(OS_MATCH_ALL, OS_MATCH_ALL, OS_MATCH_ALL, OS_NO_TIMEOUT);
- if (m) {
- gReceived++;
- if (m->mStatus != 0) { // message was considered undeliverable
- AlertUser(eUndeliverable);
- FreeMsg(m);
- }
- else {
- switch (m->mCode) {
- case DUMMYCODE+1:
- FreeMsg(m); // we don't need it any more
- GetPort(&savePort);
- SetPort(gMyWindow);
- InvalRect(&(gMyWindow->portBits.bounds)); // update the counter display
- SetPort(savePort);
- break;
- case RESETCODE+1:
- FreeMsg(m); // just discard this reply
- gReceived--; // and correct the display: we wanted to reset the counts!
- break;
-
- // handle here all the message codes you specified in your design !
-
- default:
- AlertUser(eUnknownMsg);
- m->mCode |= 0x8000; // unrecognized message code;
- m->mStatus = OS_UNKNOWN_MESSAGE; // defined in "managers.h"
- SwapTID(m);
- Send (m); // let know that you don't understand
- gSent++;
- break;
- }
- }
- UpdateDisplay();
- }
- }
-
-
- void SendaMessage(short msgCode, tid_type msgDest)
- {
- mMessage *m;
-
- m = GetMsg();
- if (m == nil)
- AlertUser(eNoMsg);
- else {
- m->mCode = msgCode;
- m->mTo = msgDest;
- // pass along mSData, mOData, mDataPtr, mDataSize as needed
- Send(m);
- gSent++;
- UpdateDisplay();
- }
- }
-
-
- void UpdateDisplay()
- {
- GrafPtr savePort;
-
- GetPort(&savePort);
- SetPort(gMyWindow);
- InvalRect(&(gMyWindow->portBits.bounds));
- SetPort(savePort);
- }
-